﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsTest
{
    /// <summary>
    /// 找连通区类
    /// </summary>
    class ConnexBlock
    {
        /// <summary>
        /// 找连通区方法
        /// </summary>
        /// <param name="im">二值矩阵</param>
        /// <param name="gs">辅助二值矩阵</param>
        /// <returns>连通区的最小外接矩形集合</returns>
        public static List<Rectangle> GetConnexBlock(byte[,] im, ref byte[,] gs)
        {
            var w = im.GetLength(0);
            var h = im.GetLength(1);
            var recList = new List<Rectangle>();
            var pointList = new List<int[]>();
            for (int j = 1; j < h - 1; j++)
            {
                for (int i = 1; i < w - 1; i++)
                {
                    if (im[i, j] == 1 && gs[i, j] == 1)
                    {
                        var point = new[] { i, j };
                        gs[i, j] = 0;
                        pointList.AddRange(getNeighborPoint(im, ref gs, point));
                        for (int k = 0; k < pointList.Count; k++)
                        {
                            pointList.AddRange(getNeighborPoint(im, ref gs, pointList[k]));
                        }

                        if (pointList.Count > 100)
                        {
                            var rec = getRecByPointList(pointList);
                            recList.Add(rec);
                        }
                        pointList = new List<int[]>();
                    }
                }
            }
            return recList;
        }

        /// <summary>
        /// 找邻域种子点
        /// </summary>
        /// <param name="im">二值矩阵</param>
        /// <param name="gs">辅助二值矩阵</param>
        /// <param name="point">种子点</param>
        /// <returns>邻域种子点集合</returns>
        private static IEnumerable<int[]> getNeighborPoint(byte[,] im, ref byte[,] gs, int[] point)
        {
            var neighborPoints = new List<int[]>();
            for (int k = -1; k < 2; k++)
            {
                for (int l = -1; l < 2; l++)
                {
                    var x = point[0] + l;
                    var y = point[1] + k;
                    if (im[x, y] == 1 && gs[x, y] == 1)
                    {
                        neighborPoints.Add(new[] { x, y });
                        gs[x, y] = 0;
                    }
                }
            }
            return neighborPoints;
        }

        /// <summary>
        /// 获取连通区的最小外接矩形
        /// </summary>
        /// <param name="pointList">连通区点的集合</param>
        /// <returns>最小外接矩形</returns>
        private static Rectangle getRecByPointList(List<int[]> pointList)
        {
            var minX = pointList[0][0];
            var minY = pointList[0][1];
            var maxX = pointList[0][0];
            var maxY = pointList[0][1];
            foreach (var point in pointList)
            {
                if (point[0] < minX)
                {
                    minX = point[0];
                }

                if (point[1] < minY)
                {
                    minY = point[1];
                }

                if (point[0] > maxX)
                {
                    maxX = point[0];
                }

                if (point[1] > maxY)
                {
                    maxY = point[1];
                }
            }
            return new Rectangle(minX - 1, minY - 1, maxX - minX + 1, maxY - minY + 1);
        }
    }
}
